#include <chrono>
#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <climits>
#include <map>

template <typename... Args> void print(const Args &...args)
{
    ((std::cout << args << " "), ...);
    std::cout << std::endl;
}

std::mutex mtx;
int mutex_var = 0;

void mutex_varaplus()
{
    while (true)
    {
        // 加锁后就保证了顺序,否则会导致两个线程交替输出,
        // t1和t2的输出就会掺杂在一起
        // 也可以使用lock_guard替换, 这样不需要手动解锁和加锁了
        // mtx.lock();
        std::lock_guard<std::mutex> lock(mtx);
        std::cout << "current thread is " << std::this_thread::get_id()
                  << std::endl;
        std::cout << "++sharad data is " << ++mutex_var << std::endl;
        // mtx.unlock();
        std::this_thread::sleep_for(std::chrono::microseconds(10));
    }
}

void mutex_varsub() { print("--mutex_var: ", --mutex_var); }

void func1()
{
    std::thread t1(mutex_varaplus);

    std::thread t2([]() {
        while (true)
        {
            // 这里lock_guard的作用域是直到跳出}的,为了提高锁的精细度可使用{}来控制

            {
                std::lock_guard<std::mutex> lock(mtx);

                // mtx.lock();
                // mutex_varsub();
                std::cout << "current thread is " << std::this_thread::get_id()
                          << std::endl;
                std::cout << "--sharad data is " << mutex_var << std::endl;
                // mtx.unlock();
            }
            // 这里的休眠不会影响业务处理,所以不必控制在锁的范围内
            std::this_thread::sleep_for(std::chrono::microseconds(10));
        }
    });
    t1.join();
    t2.join();
}
std::mutex m1;
std::mutex m2;
int m_1 = 0;
int m_2 = 0;
void dead_lock1()
{
    while (true)
    {
        print("dead_lock1 begin");
        m1.lock();
        m_1 = 1024;
        m2.lock();
        m_2 = 2048;
        m2.unlock();
        m1.unlock();
        print("dead_lock1 end");

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

void dead_lock2()
{
    while (true)
    {
        print("dead_lock2 begin");
        m2.lock();
        m_2 = 1024;
        m1.lock();
        m_1 = 2048;
        m1.unlock();
        m2.unlock();
        print("dead_lock2 end");
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}
// 避免死锁的方式:将加锁和解锁的功能封装成独立的函数
// 或者尽量不要a锁的范围内加b锁, 另一个逻辑是在b锁的范围内加a锁,多个锁也是同样的
// 把上面的两个函数封装成类似这个
void atomic_lock()
{
    while (true)
    {
        m1.lock();
        m_1 = 1024;
        m1.unlock();
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

// 这里使用lock_guard进行加锁
// 有时我们需要交换两个对象的资源, 这两个对象的内部有锁,
// 为了安全的获取资源并交换, 是需要加两次锁的, 但是容易导致死锁
// 可以使用锁来锁住锁, 这里会加三次锁, 首先使用lock(obj.锁, obj1.锁)
// 然后在使用std::lock_guard<std::mutex> g(obj.锁, std::adopt_lock)
// 同理另一个也这样写,std::adopt_lock用来告诉lock_guard或unique_lock锁已经获取了,不需要再次获取
// 如果使用了lock锁住多个锁,
// 在使用lock_guard的时候一定要使用std::adopt_lock防止死锁或者阻塞的发生
// 在C++17中可以直接使用scope_lock来为对象的锁加锁, 这样只需要一次加锁即可

// class hierarchical_mutex
// {
// public:
//     explicit hierarchical_mutex(unsigned long value)
//         : _hierarchy_value(value), _previous_hierarchy_value(0)
//     {
//     }
//     hierarchical_mutex(const hierarchical_mutex &) = delete;
//     hierarchical_mutex &operator=(const hierarchical_mutex &) = delete;
//     void lock()
//     {
//         check_for_hierarchy_violation();
//         _internal_mutex.lock();
//         update_hierarchy_value();
//     }
//     void unlock()
//     {
//         if (_this_thread_hierarchy_value != _hierarchy_value)
//         {
//             throw std::logic_error("mutex hierarchy violated");
//         }
//         _this_thread_hierarchy_value = _previous_hierarchy_value;
//         _internal_mutex.unlock();
//     }
//     bool try_lock()
//     {
//         check_for_hierarchy_violation();
//         if (!_internal_mutex.try_lock())
//         {
//             return false;
//         }
//         update_hierarchy_value();
//         return true;
//     }

// private:
//     std::mutex _internal_mutex;
//     // 当前层级值
//     unsigned long const _hierarchy_value;
//     // 上一次层级值
//     unsigned long _previous_hierarchy_value;
//     // 本线程记录的层级值
//     static thread_local unsigned long _this_thread_hierarchy_value;

// private:
//     void check_for_hierarchy_violation() const
//     {
//         if (_this_thread_hierarchy_value <= _hierarchy_value)
//         {
//             throw std::logic_error("mutex  hierarchy violated");
//         }
//     }
//     void update_hierarchy_value()
//     {
//         _previous_hierarchy_value = _this_thread_hierarchy_value;
//         _this_thread_hierarchy_value = _hierarchy_value;
//     }
// };
// thread_local unsigned long
//     hierarchical_mutex::_this_thread_hierarchy_value(ULONG_MAX);

class test
{
public:
    test(unsigned long val)
        : _hierarchy_value(val), _previous_hierarchy_value{0}
    {
    }
    test(const test &) = delete;
    test &operator=(const test &) = delete;
    void lock()
    {
        check();
        _mutex.lock();
        update();
    }
    void unlock()
    {
        if (_this_thread_hierarchy_value != _hierarchy_value)
        {
            throw std::logic_error("mutex decay");
        }
        _this_thread_hierarchy_value = _previous_hierarchy_value;
        _mutex.unlock();
    }

private:
    void check() const
    {
        if (_this_thread_hierarchy_value <= _hierarchy_value)
        {
            throw std::logic_error("logic error");
        }
    }
    void update()
    {
        _previous_hierarchy_value = _this_thread_hierarchy_value;
        _this_thread_hierarchy_value = _hierarchy_value;
    }

private:
    std::mutex _mutex;
    unsigned long const _hierarchy_value;
    static thread_local unsigned long _this_thread_hierarchy_value;
    unsigned long _previous_hierarchy_value;
};
thread_local unsigned long test::_this_thread_hierarchy_value(ULONG_MAX);
void func2()
{
    std::thread t1{dead_lock1};
    std::thread t2{dead_lock2};

    t1.join();
    t2.join();
}
void func3()
{
    // hierarchical_mutex hmtx1(1000);
    // hierarchical_mutex hmtx2(500);
    // std::thread t1([&hmtx1, &hmtx2]() {
    //     hmtx1.lock();
    //     hmtx2.lock();
    //     hmtx2.unlock();
    //     hmtx1.unlock();
    // });

    // // 除非会抛出logic_error因为前一个线程修改了thread
    // std::thread t2([&hmtx1, &hmtx2]() {
    //     hmtx2.lock();
    //     hmtx1.lock();
    //     hmtx1.unlock();
    //     hmtx2.unlock();
    // });

    // t1.join();
    // t2.join();
    std::lock_guard<std::mutex> lock(m1);

    // m1.lock();
    m1.unlock();
}

void func4()
{
    std::unique_lock<std::mutex> ulock(m1, std::defer_lock);
    ++m_1;
    ulock.lock();
    print(!ulock.owns_lock() ? "unlock" : "lock has");

    ulock.unlock();
    print(!ulock.owns_lock() ? "unlock" : "lock has");
}

void func5()
{
    std::unique_lock<std::mutex> lock(m1);
    print(lock.owns_lock() ? "lock has" : "unlock");

    std::thread t1([]() {
        std::unique_lock<std::mutex> lock(m1, std::defer_lock);
        print(!lock.owns_lock() ? "Thread lock has" : "Thread unlock");
        // 主线程未解锁, 卡在这里了, 主线程持有锁且一直没释放,
        // t线程就一直在这里阻塞了, 必须主线程解锁后才解除阻塞
        lock.lock();
        // print("hello");
        print(lock.owns_lock() ? " Thread lock has" : "Thread unlock");
        lock.unlock();
    });
    // lock.unlock();
    t1.join();
}
// 使用adopt_lock时要注意不要跨线程操作同一把锁
void func6()
{
    m1.lock();
    std::thread t([]() {
        std::unique_lock<std::mutex> lock(m1, std::adopt_lock);
        print(lock.owns_lock() ? "lock has" : "unlock");
    });
    // m1.unlock();
    t.join();
}

class DNSService
{
public:
    DNSService() = default;
    std::string QueryDNS(const std::string &dnsname) const
    {
        std::shared_lock<std::shared_mutex> lock(_shared_mtx);
        auto it = _info.find(dnsname);
        return it != _info.end() ? it->second : "";
    }

    void AddInfo(const std::string &dnsname, const std::string &entry)
    {
        std::lock_guard<std::shared_mutex> lock(_shared_mtx);
        _info.emplace(dnsname, entry);
    }

private:
    std::map<std::string, std::string> _info;
    mutable std::shared_mutex _shared_mtx;
};

class RecursiveDemo
{
public:
    RecursiveDemo() = default;
    bool QuerryStu(const std::string &name)
    {
        std::lock_guard<std::recursive_mutex> recursive_lock(_r_mutex);
        auto it = _stu_info.find(name);
        return it != _stu_info.end();
    }

    void AddScore(const std::string &name, int score)
    {
        std::lock_guard<std::recursive_mutex> r(_r_mutex);
        if (!QuerryStu(name))
        {
            _stu_info.insert({name, score});
            return;
        }
    }

    // 合并逻辑, 不提供查询服务
    void AddScoreAutomic(const std::string &name, int score)
    {
        std::lock_guard<std::recursive_mutex> r(_r_mutex);
        auto it = _stu_info.find(name);
        if (it == _stu_info.end())
        {
            _stu_info.insert({name, score});
            return;
        }
    }
    std::map<std::string, int> &getMap() { return _stu_info; }

private:
    std::map<std::string, int> _stu_info;
    std::recursive_mutex _r_mutex;
};
void func7()
{
    RecursiveDemo *rd = new RecursiveDemo();
    std::thread t([&rd]() {
        rd->AddScoreAutomic("san", 12);
        rd->AddScoreAutomic("hello", 12);
        auto m = rd->getMap();
        for (const auto &[a, b] : m)
        {
            print("thread 1");
            print(a, ": ", b);
        }
    });

    std::thread t1([&rd]() {
        rd->AddScoreAutomic("san1", 12);
        rd->AddScoreAutomic("hello1", 12);
        auto m = rd->getMap();
        for (const auto &[a, b] : m)
        {
            print("thread 2");
            print(a, ": ", b);
        }
    });
    t.join();
    t1.join();

    // print("size: ", m.size());
}

int main()
{
    // func1();
    // func2();
    // func3();
    // func4();
    // func5();
    // func6();
    func7();
    return 0;
}